#!/usr/bin/python
"""
    onmsprovision.py   -- A tool to provision information starting with OpenNMS 1.8 as part of the RESTful API
    Copyright (C) <2009>  Kirk Reeves - kirk.reeves at gmail.com

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""

import httplib
import urlparse
import urllib
import base64
from xml.dom import minidom
import sys
import getopt


URLCONNECT = 'http://localhost:8980/'
ONMS_REST = "opennms/rest"
BASE_URI =  "requisitions"
USER="admin"
PASSWD="admin"

BASEARGS = {'url' : URLCONNECT, 'username' : USER, 'password': PASSWD}

class RestData:

	def __init__(self, datatype="form", attributes = {}, **kwargs):

		if kwargs.has_key('element'):
			self._element = kwargs['element']
		else:
			self._element = None
	
		self._attr = attributes
		self._datatype = datatype
		
	def add_attributes(self,attributes):
		for attr in attributes:
			self._attr[attr] = attributes[attr]	
	
	def set_datatype(self, datatype):
		self._datatype = datatype

	def set_element(self, element):
		self._element = element

	def make_form_data(self):
		params = urllib.urlencode( self._attr )
		return params

	def make_xml_data(self):
		doc = minidom.Document()
		node_element = doc.createElement(self._element)
		
		for item in self._attr:
			node_element.setAttribute(item, self._attr[item])

		node_element.setAttribute('xmlns','http://xmlns.opennms.org/xsd/config/model-import')
	
		return node_element.toxml()
	
		
	def export_data(self):
		data = {}
		if self._datatype == 'xml':
			data['content-type'] = 'application/xml'
			data['data'] = self.make_xml_data()
		if self._datatype == 'form':
			data['content-type'] = 'application/x-www-form-urlencoded'
			data['data'] = self.make_form_data()

		return data	
		

class Connection:
	def __init__(self, base_url, username, password):
		self.base_url = base_url
		self.username = username
		self.password = password
		self.url = urlparse.urlparse(base_url)
		self.data = ""
		self.response_msg = ""
		self.status = ""

	def request_get(self, resource, args = None):
		self.request(resource, "get", args)

	def request_post(self, resource, args = None):
		self.request(resource, "post", args)
	
	def request_put(self, resource, args = None):
		self.request(resource, "put", args)

	def request_delete(self, resource, args = None):
		self.request(resource, "delete", args)

	def request(self, resource, method = "get", args = None):
		params = None
		path = resource
		headers = {}

		if self.username and self.password:
			encoded = base64.encodestring("%s:%s" % (self.username, self.password))[:-1]
			headers["Authorization"] = "Basic %s" % encoded

		if method.upper() == 'POST' or method.upper() == 'PUT':
			if args.has_key('content-type'):
				headers['Content-Type'] = args['content-type']
				headers['Content-Length'] = len(args['data'])


		if (self.url[0] == 'https'):
			conn = httplib.HTTPSConnection(self.url[1])
		else:
			conn = httplib.HTTPConnection(self.url[1])
		
		conn.set_debuglevel(0)
	
		req = conn.request(method.upper(), "/" + path, args['data'], headers)
		
		r = conn.getresponse()
	        self.response_msg = r.read()
		self.status = r.status
	
		conn.close()

		self.data = r
		return r

class ONMSRest:

	def __init__(self, **kwargs):

		self.url = ""
		self.username = ""
		self.password = ""

		if kwargs.has_key('url'): self.url = kwargs['url']
		if kwargs.has_key('username'): self.username = kwargs['username']
		if kwargs.has_key('password'): self.password = kwargs['password']

	def list_groups(self):
		pass


class ProvisionGroup(ONMSRest):

	def __init__(self, **kwargs):
		ONMSRest.__init__(self, **kwargs)

		self.group = ""
		if kwargs.has_key('group'): self.group = kwargs['group']


class RestBase(ProvisionGroup):
	
	def __init__(self, **kwargs):
		ProvisionGroup.__init__(self, **kwargs)
		self.options = {}
		self.keys = {}
		self.uri = ""
		self.method = ""
		self.data = {}
		self.attr = {}
		self.action = ''
		self.base_uri = BASE_URI
		self.conn = ''
		if kwargs.has_key('group'): self.group = kwargs['group']
	
	def add_option(self, key, value):
		self.options[key] = value

	def add_key(self, key, value):
		self.keys[key] = value

	def _set_uri(self):
		pass

	def _set_data(self):
		pass

	def _set_method(self, action):
		if action == 'add':
			self.method = 'POST'
		elif action == 'remove':
			self.method = 'DELETE'
		elif action == 'set':
			self.method = 'PUT'
		elif action == 'list':
			self.method = 'GET'
	
	def commit(self, action = ''):
		
		if action != '':
			self.action = action

		self._set_uri(self.action)
		self._set_data(self.action)
		self._set_method(self.action)

		self.conn = Connection(self.url, self.username, self.password)
        	result = self.conn.request('%s/%s' % (ONMS_REST, self.uri), self.method, self.data)

class Group(RestBase):
		def __init__(self, **kwargs):
			RestBase.__init__(self, **kwargs)
		
		def _set_uri(self, action):
		 	uri = "%s" % (self.base_uri)
			if action == 'add': 
				self.uri = uri
			elif action == 'remove':
                		self.uri = "%s/%s" % (uri,self.group)
	
		def _set_data(self, action):

			if action == 'add':
                		element = "model-import"
                		self.attr['foreign-source'] = self.group
				attributes = self.attr.copy()
				attributes.update(self.keys)
                		rest = RestData('xml', attributes, element=element)
                		self.data = rest.export_data()
			elif action == 'remove':
				self.data = {'data': None}	

class Node(RestBase):

		def __init__(self, **kwargs):
			RestBase.__init__(self, **kwargs)
			
			if self.group != '': self.add_option('source', self.group)	
			if kwargs.has_key('label'): self.add_option('node-label', kwargs['label'])
			if kwargs.has_key('id'): self.add_option('foreign-id', kwargs['id'])

		def _set_uri(self, action):

			uri = "%s/%s/nodes" % (self.base_uri, self.options['source'])

			if action == 'add': 
				self.uri = uri
			elif action == 'set':
				self.uri = "%s/%s" % (uri, self.options['foreign-id'])
			elif action == 'remove':
				self.uri = "%s/%s" % (uri, self.options['foreign-id'])

			return self.uri	
		
		def _set_data(self, action):

			if action == 'add':
				element = 'node'
                		self.attr['foreign-id'] = self.options['foreign-id']
                		self.attr['node-label'] = self.options['node-label']
				attributes = self.attr.copy()
				attributes.update(self.keys)
                		rest = RestData('xml', attributes, element=element)
                		self.data = rest.export_data()

			elif action == 'remove':
				self.data = {'data': None}	
			
			elif action == 'set':
				rest = RestData('form', self.keys)
		                self.data = rest.export_data()

class Interface(RestBase):

		def __init__(self, **kwargs):
			RestBase.__init__(self, **kwargs)
		
			if kwargs.has_key('node'): 
				self.options = kwargs['node'].options
				self.url = kwargs['node'].url
				self.username = kwargs['node'].username
				self.password = kwargs['node'].password
				self.group = kwargs['node'].group
			else:	
				if self.group != '': self.add_option('source', self.group)	
				if kwargs.has_key('label'): self.add_option('node-label', kwargs['label'])
				if kwargs.has_key('id'): self.add_option('foreign-id', kwargs['id'])
			
			if kwargs.has_key('ip'): self.add_option('ip-address', kwargs['ip'])
	
		def _set_uri(self, action):

			uri = "%s/%s/nodes/%s/interfaces" % (self.base_uri, self.group, self.options['foreign-id'])

			if action == 'add': 
				self.uri = uri
			elif action == 'set':
				self.uri = "%s/%s" % (uri, self.options['ip-address'])
			
			elif action == 'remove':
				self.uri = "%s/%s" % (uri, self.options['ip-address'])

			return self.uri	

		def _set_data(self, action):

			if action == 'add':
				element = 'interface'
                		self.attr['ip-addr'] = self.options['ip-address']
				attributes = self.attr.copy()
				attributes.update(self.keys)
                		rest = RestData('xml', attributes, element=element)
                		self.data = rest.export_data()

			elif action == 'remove':
				self.data = {}	
			
			elif action == 'set':
				rest = RestData('form', self.keys)
		                self.data = rest.export_data()


class Service(RestBase):

		def __init__(self, **kwargs):
			RestBase.__init__(self, **kwargs)
		
			if kwargs.has_key('interface'): 
				self.options = kwargs['interface'].options
				self.url = kwargs['interface'].url
				self.username = kwargs['interface'].username
				self.password = kwargs['interface'].password
				self.group = kwargs['interface'].group
			else:	
				if self.group != '': self.add_option('foreign-source', self.group)	
				if kwargs.has_key('label'): self.add_option('node-label', kwargs['label'])
				if kwargs.has_key('id'): self.add_option('foreign-id', kwargs['id'])
				if kwargs.has_key('ip'): self.add_option('ip-address', kwargs['ip'])
			
			if kwargs.has_key('service'): self.add_option('service-name', kwargs['service'])
	
		def _set_uri(self, action):

			uri = "%s/%s/nodes/%s/interfaces/%s/services" % (self.base_uri, self.group,
					 self.options['foreign-id'], self.options['ip-address'])

			if action == 'add': 
				self.uri = uri
			elif action == 'remove':
				self.uri = "%s/%s" % (uri, self.options['service-name'])

			return self.uri	

		def _set_data(self, action):

			if action == 'add':
				element = 'monitored-service'
				self.attr['service-name'] = self.options['service-name']
				attributes = self.attr.copy()
				attributes.update(self.keys)
                		rest = RestData('xml', attributes, element=element)
                		self.data = rest.export_data()

			elif action == 'remove':
				self.data = {'data' : None}	
			
class Category(RestBase):

		def __init__(self, **kwargs):
			RestBase.__init__(self, **kwargs)
		
			if kwargs.has_key('node'): 
				self.options = kwargs['node'].options
				self.url = kwargs['node'].url
				self.username = kwargs['node'].username
				self.password = kwargs['node'].password
				self.group = kwargs['node'].group
			else:	
				if self.group != '': self.add_option('source', self.group)	
				if kwargs.has_key('label'): self.add_option('node-label', kwargs['label'])
				if kwargs.has_key('id'): self.add_option('foreign-id', kwargs['id'])
			
			if kwargs.has_key('category'): self.add_option('category', kwargs['category'])
	
		def _set_uri(self, action):

			uri = "%s/%s/nodes/%s/categories" % (self.base_uri, self.group, self.options['foreign-id'])

			if action == 'add': 
				self.uri = uri
			elif action == 'set':
				self.uri = "%s/%s" % (uri, self.options['category'])
			
			elif action == 'remove':
				self.uri = "%s/%s" % (uri, self.options['category'])

			return self.uri	

		def _set_data(self, action):

			if action == 'add':
				element = 'category'
                		self.attr['name'] = self.options['category']
				attributes = self.attr.copy()
				attributes.update(self.keys)
                		rest = RestData('xml', attributes, element=element)
                		self.data = rest.export_data()

			elif action == 'remove':
				self.data = {'data' : None }	
			
			elif action == 'set':
				rest = RestData('form', self.keys)
		                self.data = rest.export_data()


class Asset(RestBase):

		def __init__(self, **kwargs):
			RestBase.__init__(self, **kwargs)
		
			if kwargs.has_key('node'): 
				self.options = kwargs['node'].options
				self.url = kwargs['node'].url
				self.username = kwargs['node'].username
				self.password = kwargs['node'].password
				self.group = kwargs['node'].group
			else:	
				if self.group != '': self.add_option('source', self.group)	
				if kwargs.has_key('label'): self.add_option('node-label', kwargs['label'])
				if kwargs.has_key('id'): self.add_option('foreign-id', kwargs['id'])
			
			if kwargs.has_key('name'): self.add_option('name', kwargs['name'])
			if kwargs.has_key('value'): self.add_option('value', kwargs['value'])
	
		def _set_uri(self, action):

			uri = "%s/%s/nodes/%s/assets" % (self.base_uri, self.group, self.options['foreign-id'])

			if action == 'add': 
				self.uri = uri
			elif action == 'set':
				self.uri = "%s/%s" % (uri, self.options['asset'])
			
			elif action == 'remove':
				self.uri = "%s/%s" % (uri, self.options['asset'])

			return self.uri	

		def _set_data(self, action):

			if action == 'add':
				element = 'asset'
                		self.attr['name'] = self.options['name']
                		self.attr['value'] = self.options['value']
				attributes = self.attr.copy()
				attributes.update(self.keys)
                		rest = RestData('xml', attributes, element=element)
                		self.data = rest.export_data()

			elif action == 'remove':
				self.data = {'data' : None }	
			

